package com.gitee.wsl.common.chart.render.foreground.info

import android.graphics.Canvas
import android.graphics.Color
import android.graphics.Paint
import android.graphics.RectF
import com.gitee.wsl.common.chart.ChartEnum
import com.gitee.wsl.common.chart.model.PlotDot
import com.gitee.wsl.common.draw.area.Viewport
import com.gitee.wsl.common.chart.render.foreground.border.BorderDrawableReader
import com.gitee.wsl.common.chart.render.shape.plot.renderDot
import com.gitee.wsl.common.chart.sample.XChart
import com.gitee.wsl.common.ui.draw.type.DotStyle
import com.gitee.wsl.common.ui.draw.type.HorizontalAlign
import com.gitee.wsl.common.ui.draw.type.VerticalAlign
import com.gitee.wsl.android.ui.ext.type.textHeight
import com.gitee.wsl.android.ui.ext.type.textWidth
import com.gitee.wsl.mathematics.geometry.shape.Rectangle


/**
 *
 * @Description 用于设定图例的属性
 * @author XiongChuanLiang<br/>(xcl_168@aliyun.com)
 *
 */
class PlotLegend(val mXChart: XChart): Rectangle() {
    //数据集的说明描述与图这间的空白间距
    var margin = 10f

    //数据集的说明描述画笔
    val keyPaint: Paint by lazy {
        Paint().apply {
            color = Color.BLACK
            isAntiAlias = true
            textSize = 15f
        }
    }

    //是否显示图例
    var isVisible = true

    //图例起始偏移多少距离
    var offsetX = 0.0f
    var offsetY = 0.0f

    //行间距
    var rowSpan = 10.0f
    var colSpan = 10.0f

    //图例方向
    /*
        private ChartEnum.LegendType mLegendType = ChartEnum.LegendType.COLUMN;
        private ChartEnum.HorizontalAlign mHorizontalAlign = ChartEnum.HorizontalAlign.RIGHT;
        private ChartEnum.VerticalAlign mVerticalAlign = ChartEnum.VerticalAlign.MIDDLE;
         */
    var legendType = ChartEnum.LegendType.ROW
    var horizontalAlign = HorizontalAlign.LEFT
    var verticalAlign = VerticalAlign.TOP

    //box
    val borderReader: BorderDrawableReader by lazy {
        BorderDrawableReader(this)
    }

    var isShowBox = true
        set(value) {
            field = value
            if (value) {
                isShowBoxBorder = true
                isShowBackground = true
            }
        }

    var isShowBoxBorder by borderReader::isShowBorder
    var isShowBackground by borderReader::isShowBackground

    //private static final String TAG = "PlotLegendRender";
     var plotViewport: Viewport? = null

     var keyLabelX = 0.0f
     var keyLabelY = 0.0f

    /////////////////////////////////////
    var lstDotStyle = mutableListOf<PlotDot>()
    var lstKey = mutableListOf<String>()
    var lstColor = mutableListOf<Int>()

     var rectWidth = 0.0f
     var rectHeight = 0.0f

    var mapID = LinkedHashMap<Int, Int>()

     val isLnChart = false
     val linePaint: Paint = Paint()

    enum class EnumChartType {
        AXIS, CIR, LN, RD
    }

    var mType = EnumChartType.AXIS


    fun draw(canvas: Canvas, dataSet: List<PlotLegendItem>): Boolean {
        if (!isVisible) return false
        refreshLst()
        //convertArrayKey(dataSet)
        dataSet.forEach {
            addLegend(it)
        }
        render(canvas)
        return true
    }

    private fun initEnv() {
        keyLabelY = 0.0f
        keyLabelX = keyLabelY
        rectHeight = 0.0f
        rectWidth = rectHeight
    }

    fun render(canvas: Canvas) {
        if (null == plotViewport) plotViewport = mXChart.plotViewport
        calcContentRect()
        getStartXY()
        drawLegend(canvas)
    }

    @JvmName("getRectWidth1")
    private fun getRectWidth(): Float {
        var rectWidth = 0.0f
        val textHeight: Float = getLabelTextHeight()
        rectWidth = if (isLnChart) {
            2 * textHeight
        } else {
            textHeight / 2 + textHeight
        }
        return rectWidth
    }

     private fun calcContentRect() {
        val countDots = lstDotStyle.size
        val countText = lstKey.size
        if (0 == countText && 0 == countDots) return
        //int count = (countText > countDots)?countText:countDots;
        var text = ""
        val textHeight: Float = getLabelTextHeight()
        var row = 1
        mapID.clear()
        val areaWidth = plotViewport!!.width - 2 * margin
        val rectWidth = getRectWidth()
        var rowWidth = 0.0f
        var maxHeight = textHeight
        var maxWidth = 0.0f
        for (i in 0 until countText) {
            if (countDots > i) {
                val plot = lstDotStyle[i]
                if (isLnChart) {
                    rowWidth += rectWidth + colSpan
                } else {
                    if (plot.dotStyle != DotStyle.HIDE) rowWidth += rectWidth + colSpan
                }
            }
            text = lstKey[i]
            val labelWidth: Float = getLabelTextWidth(text)
            rowWidth += labelWidth
            when (legendType) {
                ChartEnum.LegendType.ROW -> if (rowWidth.compareTo(areaWidth) == 1
                ) {    //换行
                    rowWidth = rectWidth + colSpan + labelWidth
                    maxHeight += textHeight + rowSpan
                    row++
                } else {
                    rowWidth += colSpan
                    if (rowWidth.compareTo(maxWidth) == 1) maxWidth = rowWidth
                }

                ChartEnum.LegendType.COLUMN -> {
                    if (rowWidth.compareTo(maxWidth) == 1) maxWidth = rowWidth
                    maxHeight += textHeight + rowSpan
                    rowWidth = 0.0f
                    row++
                }

                else -> {}
            }
            mapID[i] = row
        }
        this.rectWidth = maxWidth + 2 * margin
        rectHeight = maxHeight + 2 * margin
        if (ChartEnum.LegendType.COLUMN == legendType) rectHeight -= 2 * rowSpan
    }


    private fun getStartXY() {
        var mBoxLineSize = BOX_LINE_SIZE.toFloat()
        if (!isShowBox) mBoxLineSize = 0.0f
        when (horizontalAlign) {
            HorizontalAlign.LEFT -> {
                keyLabelX = if (EnumChartType.CIR == mType) {
                    mXChart.left + offsetX
                } else {
                    plotViewport!!.left + offsetX
                }
                keyLabelX += mBoxLineSize
            }

            HorizontalAlign.CENTER -> keyLabelX =
                mXChart.left + (mXChart.width - rectWidth) / 2 + offsetX

            HorizontalAlign.RIGHT -> {
                keyLabelX = if (EnumChartType.CIR == mType) {
                    mXChart.right - offsetX - rectWidth
                } else {
                    plotViewport!!.right - offsetX - rectWidth
                }
                keyLabelX -= mBoxLineSize
            }

            else -> {}
        }
        when (verticalAlign) {
            VerticalAlign.TOP -> if (ChartEnum.LegendType.COLUMN == legendType) {
                keyLabelY = plotViewport!!.top + offsetY
                keyLabelY += mBoxLineSize
            } else {
                keyLabelY = plotViewport!!.top - rectHeight - offsetY
                keyLabelY -= mBoxLineSize
            }

            VerticalAlign.MIDDLE -> keyLabelY =
                plotViewport!!.top + (plotViewport!!.height - rectHeight) / 2

            VerticalAlign.BOTTOM -> if (ChartEnum.LegendType.COLUMN == legendType) {
                keyLabelY = mXChart.bottom + offsetY
                keyLabelY += mXChart.borderWidth
                keyLabelY += mBoxLineSize
            } else {
                keyLabelY = mXChart.bottom - rectHeight - offsetY
                keyLabelY -= mXChart.borderWidth
                keyLabelY -= mBoxLineSize
            }

            else -> {}
        }
    }


    private fun drawLegend(canvas: Canvas) {
        val countDots = lstDotStyle.size
        val countText = lstKey.size
        if (0 == countText && 0 == countDots) return
        val countColor = lstColor.size
        val currDotsX = keyLabelX + margin
        var currRowX = currDotsX
        var currRowY = keyLabelY + margin
        val textHeight: Float = getLabelTextHeight()
        val rectWidth = getRectWidth() //2 * textHeight;
        var currRowID = 0
        val iter: Iterator<*> = mapID.entries.iterator()

        //背景
        drawBox(canvas)

        //图例
        while (iter.hasNext()) {
            val (key, value) = iter.next() as Map.Entry<*, *>
            val id = key as Int
            val row = value as Int //行号
            if (row > currRowID) //换行
            {
                if (0 < currRowID) currRowY += textHeight + rowSpan
                currRowX = keyLabelX + margin
                currRowID = row
            }

            //颜色
            if (countColor > id) {
                keyPaint.color = lstColor[id]
                if (isLnChart) linePaint.color = lstColor[id]
            } else {
                keyPaint.color = Color.BLACK
                if (isLnChart) linePaint.color = Color.BLACK
            }
            if (countDots > id) {
                val plot = lstDotStyle[id]
                if (isLnChart) //line
                {
                    canvas.drawLine(
                        currRowX, currRowY + textHeight / 2,
                        currRowX + rectWidth, currRowY + textHeight / 2,
                        linePaint
                    )
                    canvas.renderDot(
                        plot,
                        currRowX + rectWidth / 2,
                        currRowY + textHeight / 2,
                        keyPaint
                    )
                    currRowX += rectWidth + colSpan
                } else {
                    if (plot.dotStyle != DotStyle.HIDE) {
                        canvas.renderDot(
                            plot,
                            currRowX + rectWidth / 2,
                            currRowY + textHeight / 2,
                            keyPaint
                        )
                        currRowX += rectWidth + colSpan
                    }
                }
            }
            val label = lstKey[id]
            if ("" !== label) canvas.drawText(
                label,
                currRowX,
                currRowY + textHeight,
                keyPaint
            )
            currRowX += this.getLabelTextWidth(label)
            currRowX += colSpan
        }
        mapID.clear()
        clearLst()
    }

    protected fun getLabelTextHeight(): Float {
        return keyPaint.textHeight
    }


    protected fun getLabelTextWidth(label: String): Float {
        return keyPaint.textWidth(label)
    }

    fun clearLst() {
        lstDotStyle.clear()
        lstKey.clear()
        lstColor.clear()
    }


    private fun drawBox(canvas: Canvas) {
        if (!isShowBox) return
        val rect = RectF()
        rect.left = keyLabelX
        rect.right = keyLabelX + rectWidth
        rect.top = keyLabelY
        rect.bottom = keyLabelY + rectHeight
        borderReader.renderRect(canvas, rect, isShowBoxBorder, isShowBackground)
    }

    private fun refreshLst() {
        initEnv()
        lstKey.clear()
        lstDotStyle.clear()
        lstColor.clear()
    }

    ////////////////////////////////

    protected fun isDrawKey(key: String): Boolean {
        return !("" === key || key.isEmpty())
    }

    /**
     * 增加动态图例
     * @param dotStyle        图案风格
     * @param text            文本
     * @param paint            画笔
     */
    fun addLegend(dotStyle: PlotDot, text: String, color: Int) {
        lstDotStyle.add(dotStyle)
        lstKey.add(text)
        lstColor.add(color)
    }

    fun addLegend(item: PlotLegendItem) {
        addLegend(item.mLstDotStyle, item.mLstKey, item.mLstColor)
    }

    fun hide() {
        isVisible=false
    }

    fun show() {
        isVisible=true
    }

    companion object {
        //此处的5.f相当于this.getBox().getLinePaint()的高度
        private val BOX_LINE_SIZE = 5
    }

}


class PlotLegendItem(
    var mLstKey: String,
    var mLstColor: Int,
    var mLstDotStyle: PlotDot
)